﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;

namespace OL.FrameCore.Infrastructure.UnitOfWork
{
    public class EFUnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext
    {
        TContext _dbContext;
        Dictionary<Type, object> dictRepository;

        public EFUnitOfWork(TContext dbContext)
        {
            _dbContext = dbContext;
        }

        public TContext DbContext => _dbContext;

        public IRepositoryBase<TEntity> GetRepository<TEntity>() where TEntity : class
        {
            //var repository = new RepositoryBase<TEntity>(_dbContext);
            //return repository;
            if (dictRepository == null)
            {
                dictRepository = new Dictionary<Type, object>();
            }
            Type type = typeof(TEntity);
            if (!this.dictRepository.ContainsKey(type))
            {
                this.dictRepository[type] = new RepositoryBase<TEntity>(this._dbContext);
            }
            return (IRepositoryBase<TEntity>)this.dictRepository[type];
            
        }

        public void Save()
        {
            _dbContext.SaveChanges();
        }

        //public void ExecuteSqlQuery(string sql)
        //{
        //    _dbContext.Database.SqlQuery<UserInfo>("select* from UserInfoes ").ToList();
        //}
        public IList<T> SqlQuery<T>(string sql, params object[] parameters)
            where T : new()
        {
            //注意：不要对GetDbConnection获取到的conn进行using或者调用Dispose，否则DbContext后续不能再进行使用了，会抛异常
            var conn = _dbContext.Database.GetDbConnection();
            try
            {
                conn.Open();
                using (var command = conn.CreateCommand())
                {
                    command.CommandText = sql;
                    command.Parameters.AddRange(parameters);
                    var propts = typeof(T).GetProperties();
                    var rtnList = new List<T>();
                    T model;
                    object val;
                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            model = new T();
                            foreach (var l in propts)
                            {
                                val = reader[l.Name];
                                if (val == DBNull.Value)
                                {
                                    l.SetValue(model, null);
                                }
                                else
                                {
                                    l.SetValue(model, val);
                                }
                            }
                            rtnList.Add(model);
                        }
                    }
                    return rtnList;
                }
            }
            finally
            {
                conn.Close();
            }
        }

        public int ExecuteSqlCommand(string sql, params object[] parameters)
        {
            return _dbContext.Database.ExecuteSqlCommand(sql, parameters);
        }
    }
}
